/* vim: set ts=2 et sw=2 cindent fo=qroca: */

package com.globant.google.mendoza.malbec;

import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.globant.google.mendoza.malbec.schema._2.CheckoutShoppingCart;
import com.globant.google.mendoza.malbec.schema._2.ObjectFactory;

/** This class implements the un-marshalling of notification messages from the
 * GBuy server to the OrderListener implementation.
 *
 * The notification dispatcher must be registered in the transport as a
 * receiver. When a message arrives it unmarshalls the parameters and calls the
 * corresponding method in the OrderListener.
 */
public final class CartUtils {

  /** The class logger.
   */
  private static Log log = LogFactory.getLog(CartUtils.class);

  /** The shared JAXB context used to unmarshal all notifications.
   */
  private static JAXBContext context;

  static {
    try {
      context = JAXBContext.newInstance(//NotificationObjectFactory.class);
          "com.globant.google.mendoza.malbec.schema._2");
    } catch (JAXBException e) {
      throw new RuntimeException("Error initializing JAXB context", e);
    }
  }

  /** Private constructor so no instances can be created.
   */
  private CartUtils() {
    // Nothing to do.
  }

  /** Unmarshals an xml message.
   *
   * @param message The xml message to unmarshal.
   *
   * @return Returns a jaxb generated object deserialized from the xml message.
   */
  public static JAXBElement unmarshal(final String message) {
    log.trace("Entering unmarshal");
    JAXBElement node = null;
    try {
      Unmarshaller unmarshaller = context.createUnmarshaller();
      unmarshaller.setProperty("com.sun.xml.bind.ObjectFactory",
          new NotificationObjectFactory());
      node = (JAXBElement) unmarshaller.unmarshal(new StringReader(message));
    } catch (JAXBException e) {
      throw new RuntimeException("Error parsing message", e);
    }
    log.trace("Leaving unmarshal");
    return node;
  }

  /** Marshals a jaxb generated object to an xml string.
   *
   * @param object The jaxb generatod object.
   *
   * @return Returns a xml strirng.
   */
  public static String marshal(final JAXBElement object) {
    return marshal(object, false);
  }

  /** Marshals a jaxb generated object to an xml string.
   *
   * @param object The jaxb generatod object.
   *
   * @param formattedOuputOn The jaxb formatted output option.
   *
   * @return Returns a xml strirng.
   */
  public static String marshal(final JAXBElement object,
      final boolean formattedOuputOn) {
    log.trace("Entering marshal");
    String content = null;
    try {
      Marshaller marshaller = context.createMarshaller();
      if (formattedOuputOn) {
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
      }
      ByteArrayOutputStream stream = new ByteArrayOutputStream();
      marshaller.marshal(object, stream);
      content = stream.toString("UTF-8");

    } catch (UnsupportedEncodingException e) {
      // This should never happen.
      throw new RuntimeException("Error marshalling jaxb object", e);
    } catch (JAXBException e) {
      throw new RuntimeException("Error marshalling jaxb object", e);
    }
    log.trace("Leaving marshal");
    return content;
  }

  /** Obtains the Checkout shopping cart in xml.
   *
   * @param cart The cart as generated by jaxb. It cannot be null.
   *
   * @return Returns a xml string.
   */
  public static String toXml(final CheckoutShoppingCart cart) {
    ObjectFactory factory = new ObjectFactory();
    return marshal(factory.createCheckoutShoppingCart(cart));
  }
}

